package com.mall.system.service;

import com.mall.common.constant.UserConstants;
import com.mall.common.core.domain.Ztree;
import com.mall.common.utils.StringUtils;
import com.mall.system.domain.entity.SysMenu;
import com.mall.system.domain.entity.SysRole;
import com.mall.system.domain.entity.SysUser;
import com.mall.system.mapper.SysMenuMapper;
import com.mall.system.mapper.SysRoleMenuMapper;
import java.text.MessageFormat;
import java.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 菜单 业务层处理
 * Created by zhonglin on 2020/4/8.
 */
@Service
public class SysMenuService {

  public static final String PREMISSION_STRING = "perms[\"{0}\"]";

  @Autowired
  private SysMenuMapper menuMapper;

  @Autowired
  private SysRoleMenuMapper roleMenuMapper;

  /**
   * 根据用户查询菜单
   *
   * @param user 用户信息
   * @return 菜单列表
   */
  public List<SysMenu> selectMenusByUser(SysUser user) {

    List<SysMenu> menus = new LinkedList<SysMenu>();
    // 管理员显示所有菜单信息
    if (user.isAdmin()) {
      menus = menuMapper.selectMenuNormalAll();
    } else {
      menus = menuMapper.selectMenusByUserId(user.getUserId());
    }
    return getChildPerms(menus, 0);
  }

  /**
   * 查询菜单集合
   *
   * @return 所有菜单信息
   */
  public List<SysMenu> selectMenuList(SysMenu menu,
                                      Long userId) {

    List<SysMenu> menuList = null;
    if (SysUser.isAdmin(userId)) {
      menuList = menuMapper.selectMenuList(menu);
    } else {
      menu.getParams()
          .put("userId", userId);
      menuList = menuMapper.selectMenuListByUserId(menu);
    }
    return menuList;
  }

  /**
   * 查询菜单集合
   *
   * @return 所有菜单信息
   */
  public List<SysMenu> selectMenuAll(Long userId) {

    List<SysMenu> menuList = null;
    if (SysUser.isAdmin(userId)) {
      menuList = menuMapper.selectMenuAll();
    } else {
      menuList = menuMapper.selectMenuAllByUserId(userId);
    }
    return menuList;
  }

  /**
   * 根据用户ID查询权限
   *
   * @param userId 用户ID
   * @return 权限列表
   */
  public Set<String> selectPermsByUserId(Long userId) {

    List<String> perms    = menuMapper.selectPermsByUserId(userId);
    Set<String>  permsSet = new HashSet<>();
    for (String perm : perms) {
      if (StringUtils.isNotEmpty(perm)) {
        permsSet.addAll(Arrays.asList(perm.trim()
                                          .split(",")));
      }
    }
    return permsSet;
  }

  /**
   * 根据角色ID查询菜单
   *
   * @param role 角色对象
   * @return 菜单列表
   */
  public List<Ztree> roleMenuTreeData(SysRole role,
                                      Long userId) {

    Long          roleId   = role.getRoleId();
    List<Ztree>   ztrees   = new ArrayList<Ztree>();
    List<SysMenu> menuList = selectMenuAll(userId);
    if (StringUtils.isNotNull(roleId)) {
      List<String> roleMenuList = menuMapper.selectMenuTree(roleId);
      ztrees = initZtree(menuList, roleMenuList, true);
    } else {
      ztrees = initZtree(menuList, null, true);
    }
    return ztrees;
  }

  /**
   * 查询所有菜单
   *
   * @return 菜单列表
   */
  public List<Ztree> menuTreeData(Long userId) {

    List<SysMenu> menuList = selectMenuAll(userId);
    List<Ztree>   ztrees   = initZtree(menuList);
    return ztrees;
  }

  /**
   * 查询系统所有权限
   *
   * @return 权限列表
   */
  public LinkedHashMap<String, String> selectPermsAll(Long userId) {

    LinkedHashMap<String, String> section     = new LinkedHashMap<>();
    List<SysMenu>                 permissions = selectMenuAll(userId);
    if (StringUtils.isNotEmpty(permissions)) {
      for (SysMenu menu : permissions) {
        section.put(menu.getUrl(), MessageFormat.format(PREMISSION_STRING, menu.getPerms()));
      }
    }
    return section;
  }

  /**
   * 对象转菜单树
   *
   * @param menuList 菜单列表
   * @return 树结构列表
   */
  public List<Ztree> initZtree(List<SysMenu> menuList) {

    return initZtree(menuList, null, false);
  }

  /**
   * 对象转菜单树
   *
   * @param menuList 菜单列表
   * @param roleMenuList 角色已存在菜单列表
   * @param permsFlag 是否需要显示权限标识
   * @return 树结构列表
   */
  public List<Ztree> initZtree(List<SysMenu> menuList,
                               List<String> roleMenuList,
                               boolean permsFlag) {

    List<Ztree> ztrees  = new ArrayList<Ztree>();
    boolean     isCheck = StringUtils.isNotNull(roleMenuList);
    for (SysMenu menu : menuList) {
      Ztree ztree = new Ztree();
      ztree.setId(menu.getMenuId());
      ztree.setpId(menu.getParentId());
      ztree.setName(transMenuName(menu, permsFlag));
      ztree.setTitle(menu.getMenuName());
      if (isCheck) {
        ztree.setChecked(roleMenuList.contains(menu.getMenuId() + menu.getPerms()));
      }
      ztrees.add(ztree);
    }
    return ztrees;
  }

  public String transMenuName(SysMenu menu,
                              boolean permsFlag) {

    StringBuffer sb = new StringBuffer();
    sb.append(menu.getMenuName());
    if (permsFlag) {
      sb.append("<font color=\"#888\">&nbsp;&nbsp;&nbsp;" + menu.getPerms() + "</font>");
    }
    return sb.toString();
  }

  /**
   * 删除菜单管理信息
   *
   * @param menuId 菜单ID
   * @return 结果
   */
  public int deleteMenuById(Long menuId) {

    return menuMapper.deleteMenuById(menuId);
  }

  /**
   * 根据菜单ID查询信息
   *
   * @param menuId 菜单ID
   * @return 菜单信息
   */
  public SysMenu selectMenuById(Long menuId) {

    return menuMapper.selectMenuById(menuId);
  }

  /**
   * 查询子菜单数量
   *
   * @param parentId 父级菜单ID
   * @return 结果
   */
  public int selectCountMenuByParentId(Long parentId) {

    return menuMapper.selectCountMenuByParentId(parentId);
  }

  /**
   * 查询菜单使用数量
   *
   * @param menuId 菜单ID
   * @return 结果
   */
  public int selectCountRoleMenuByMenuId(Long menuId) {

    return roleMenuMapper.selectCountRoleMenuByMenuId(menuId);
  }

  /**
   * 新增保存菜单信息
   *
   * @param menu 菜单信息
   * @return 结果
   */
  public int insertMenu(SysMenu menu) {

    return menuMapper.insertMenu(menu);
  }

  /**
   * 修改保存菜单信息
   *
   * @param menu 菜单信息
   * @return 结果
   */
  public int updateMenu(SysMenu menu) {

    return menuMapper.updateMenu(menu);
  }

  /**
   * 校验菜单名称是否唯一
   *
   * @param menu 菜单信息
   * @return 结果
   */
  public String checkMenuNameUnique(SysMenu menu) {

    Long    menuId = StringUtils.isNull(menu.getMenuId())
        ? -1L
        : menu.getMenuId();
    SysMenu info   = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId());
    if (StringUtils.isNotNull(info) && info.getMenuId()
                                           .longValue() != menuId.longValue()) {
      return UserConstants.MENU_NAME_NOT_UNIQUE;
    }
    return UserConstants.MENU_NAME_UNIQUE;
  }

  /**
   * 根据父节点的ID获取所有子节点
   *
   * @param list 分类表
   * @param parentId 传入的父节点ID
   * @return String
   */
  public List<SysMenu> getChildPerms(List<SysMenu> list,
                                     int parentId) {

    List<SysMenu> returnList = new ArrayList<SysMenu>();
    for (Iterator<SysMenu> iterator = list.iterator();
         iterator.hasNext(); ) {
      SysMenu t = (SysMenu) iterator.next();
      // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
      if (t.getParentId() == parentId) {
        recursionFn(list, t);
        returnList.add(t);
      }
    }
    return returnList;
  }

  /**
   * 递归列表
   *
   * @param list
   * @param t
   */
  private void recursionFn(List<SysMenu> list,
                           SysMenu t) {
    // 得到子节点列表
    List<SysMenu> childList = getChildList(list, t);
    t.setChildren(childList);
    for (SysMenu tChild : childList) {
      if (hasChild(list, tChild)) {
        // 判断是否有子节点
        Iterator<SysMenu> it = childList.iterator();
        while (it.hasNext()) {
          SysMenu n = (SysMenu) it.next();
          recursionFn(list, n);
        }
      }
    }
  }

  /**
   * 得到子节点列表
   */
  private List<SysMenu> getChildList(List<SysMenu> list,
                                     SysMenu t) {

    List<SysMenu>     tlist = new ArrayList<SysMenu>();
    Iterator<SysMenu> it    = list.iterator();
    while (it.hasNext()) {
      SysMenu n = (SysMenu) it.next();
      if (n.getParentId()
           .longValue() == t.getMenuId()
                            .longValue()) {
        tlist.add(n);
      }
    }
    return tlist;
  }

  /**
   * 判断是否有子节点
   */
  private boolean hasChild(List<SysMenu> list,
                           SysMenu t) {

    return getChildList(list, t).size() > 0
        ? true
        : false;
  }

}
